package cn.restcloud.springboot.config;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.commons.lang3.StringUtils;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoCredential;
import com.mongodb.ReadPreference;
import com.mongodb.ServerAddress;

import cn.restcloud.framework.core.context.AppContext;
import cn.restcloud.framework.core.context.ServletInitApplication;
import cn.restcloud.framework.core.util.CommonUtil;
import cn.restcloud.framework.core.util.ConfigUtil;
import cn.restcloud.springboot.init.SpringbootUtil;


@Component
public class RestCloudContextAware  implements ApplicationContextAware{

	@Autowired
	Scheduler scheduler;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		SpringbootUtil.setApplicationContext(applicationContext);
		MongoClient mongoClient=null; //平台mongodb链接
		MongoClient logMongoClient=null;//平台log mongodb链接
		if(!AppContext.getDataInLocalJsonFile()) {
			//数据存储在mongodb中,链接mongodb
			if(applicationContext.containsBean("mongo")) {
				mongoClient=(MongoClient) applicationContext.getBean("mongo");
			}else {
				mongoClient=getPlatformMongoClient();
			}
	        //初始化restcloud,并注入平台的monogdb数据源
			logMongoClient=getLogMongoClient();
		}
        ServletInitApplication.init(mongoClient,logMongoClient,scheduler);
	}
	
	
	/**
	 * 指定平台所使用的mongodb数据库链接配置
	 * @return
	 */
	public MongoClient getPlatformMongoClient() {
			String authenticationDatabase=ConfigUtil.getLocalConfig("spring.data.mongodb.authentication-database","admin");
			String username=ConfigUtil.getLocalConfig("spring.data.mongodb.username"); //用户名
			String password=ConfigUtil.getLocalConfig("spring.data.mongodb.password"); //密码
			int maxConnectionsPerHost =Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.max-connections-per-host", "500"));//每个host允许链接的最大链接数,这些链接空闲时会放入池中,如果链接被耗尽，任何请求链接的操作会被阻塞等待链接可用,推荐配置10
			int minConnectionsPerHost =Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.min-connections-per-host", "0"));
			String replicaSet=ConfigUtil.getLocalConfig("replicaSet");
			int threadsAllowedToBlockForConnectionMultiplier =Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.threads-allowed-toblock-for-connection-multiplier", "5"));
			int localThreshold =Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.local-threshold", "15"));
			List<String> addressList=CommonUtil.splitAsList(ConfigUtil.getLocalConfig("spring.data.mongodb.host","127.0.0.1:27017"),",");
			int serverSelectionTimeout =Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.server-selection-timeout", "3000")); //3秒内找到可用服务器，否则认为mongodb服务器链接不可用
			int maxWaitTime=Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.max-wait-time", "30000")); //从集合中获取数据的最大等待时间30秒，30秒内没有查询完数据就超时
			int maxConnectionIdleTime=Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.max-connection-idel-time", "0"));
			int maxConnectionLifeTime =Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.max-connection-life-time", "0"));
			int connectTimeout =Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.connect-timeout", "3000")); //获取服务器后，3秒内与服务器建立链接，如果没有建立起链接就超时
			String readPreference=ConfigUtil.getLocalConfig("spring.data.mongodb.readPreference", "");
			
			//客户端配置（连接数，副本集群验证）
			MongoClientOptions.Builder builder = new MongoClientOptions.Builder();
			builder.connectionsPerHost(maxConnectionsPerHost);
			builder.minConnectionsPerHost(minConnectionsPerHost);
			if (StringUtils.isNotBlank(replicaSet)) {
				builder.requiredReplicaSetName(replicaSet);
			}
			builder.threadsAllowedToBlockForConnectionMultiplier(threadsAllowedToBlockForConnectionMultiplier);
			builder.localThreshold(localThreshold);
			builder.serverSelectionTimeout(serverSelectionTimeout);
			builder.maxWaitTime(maxWaitTime);
			builder.maxConnectionIdleTime(maxConnectionIdleTime);
			builder.maxConnectionLifeTime(maxConnectionLifeTime);
			builder.connectTimeout(connectTimeout);
			
			//主从读取模式配置
			if(StringUtils.isNotBlank(readPreference)) {
				if(readPreference.equalsIgnoreCase("secondaryPreferred")) {
					builder.readPreference(ReadPreference.secondaryPreferred());
				}else if(readPreference.equalsIgnoreCase("nearest")) {
					builder.readPreference(ReadPreference.nearest());
				}else if(readPreference.equalsIgnoreCase("primaryPreferred")) {
					builder.readPreference(ReadPreference.primaryPreferred());
				}else if(readPreference.equalsIgnoreCase("secondary")) {
					builder.readPreference(ReadPreference.secondary());
				}
			}
			
			MongoClientOptions mongoClientOptions = builder.build();
			// MongoDB地址列表
			List<ServerAddress> serverAddresses = new ArrayList<>();
			for (String address : addressList) {
				String[] hostAndPort = address.split(":");
				String host = hostAndPort[0];
				Integer port=27017;
				if(hostAndPort.length>1) {
					port = Integer.parseInt(hostAndPort[1]);
				}
				ServerAddress serverAddress = new ServerAddress(host, port);
				serverAddresses.add(serverAddress);
			}
			
			MongoClient mongoClient;
			if(StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password)) {
				//认证链接
				MongoCredential mongoCredential = MongoCredential.createScramSha1Credential(username,authenticationDatabase,password.toCharArray());
				mongoClient = new MongoClient(serverAddresses, mongoCredential, mongoClientOptions);
			}else {
				//无需认证链接
				mongoClient = new MongoClient(serverAddresses, mongoClientOptions);
			}
			
			return mongoClient;
	}
	
	/**
	 * 指定日记库所使用的mongodb数据库链接配置
	 * @return
	 */
	public MongoClient getLogMongoClient() {
			String authenticationDatabase=ConfigUtil.getLocalConfig("spring.data.mongodb.log.authentication-database");
			if(StringUtils.isBlank(authenticationDatabase)) {return null;} //说明没有配置日记数据源
			
			String username=ConfigUtil.getLocalConfig("spring.data.mongodb.log.username"); //用户名
			String password=ConfigUtil.getLocalConfig("spring.data.mongodb.log.password"); //密码
			int maxConnectionsPerHost =Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.log.max-connections-per-host", "500"));//每个host允许链接的最大链接数,这些链接空闲时会放入池中,如果链接被耗尽，任何请求链接的操作会被阻塞等待链接可用,推荐配置10
			int minConnectionsPerHost =Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.log.min-connections-per-host", "0"));
			String replicaSet=ConfigUtil.getLocalConfig("log.replicaSet"); //副本集群验证
			int threadsAllowedToBlockForConnectionMultiplier =Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.log.threads-allowed-toblock-for-connection-multiplier", "5"));
			int localThreshold =Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.log.local-threshold", "15"));
			List<String> addressList=CommonUtil.splitAsList(ConfigUtil.getLocalConfig("spring.data.mongodb.log.host","127.0.0.1:27017"),",");
			int serverSelectionTimeout =Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.log.server-selection-timeout", "3000")); //3秒内找到可用服务器，否则认为mongodb服务器链接不可用
			int maxWaitTime=Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.log.max-wait-time", "30000")); //从集合中获取数据的最大等待时间30秒，30秒内没有查询完数据就超时
			int maxConnectionIdleTime=Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.log.max-connection-idel-time", "0"));
			int maxConnectionLifeTime =Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.log.max-connection-life-time", "0"));
			int connectTimeout =Integer.parseInt(ConfigUtil.getLocalConfig("spring.data.mongodb.log.connect-timeout", "3000")); //获取服务器后，3秒内与服务器建立链接，如果没有建立起链接就超时
			String readPreference=ConfigUtil.getLocalConfig("spring.data.mongodb.readPreference", "");
			
			//客户端配置（连接数，副本集群验证）
			MongoClientOptions.Builder builder = new MongoClientOptions.Builder();
			builder.connectionsPerHost(maxConnectionsPerHost);
			builder.minConnectionsPerHost(minConnectionsPerHost);
			if (StringUtils.isNotBlank(replicaSet)) {
				builder.requiredReplicaSetName(replicaSet);
			}
			builder.threadsAllowedToBlockForConnectionMultiplier(threadsAllowedToBlockForConnectionMultiplier);
			builder.localThreshold(localThreshold);
			builder.serverSelectionTimeout(serverSelectionTimeout);
			builder.maxWaitTime(maxWaitTime);
			builder.maxConnectionIdleTime(maxConnectionIdleTime);
			builder.maxConnectionLifeTime(maxConnectionLifeTime);
			builder.connectTimeout(connectTimeout);
			
			//主从读取模式配置
			if(StringUtils.isNotBlank(readPreference)) {
				if(readPreference.equalsIgnoreCase("secondaryPreferred")) {
					builder.readPreference(ReadPreference.secondaryPreferred());
				}else if(readPreference.equalsIgnoreCase("nearest")) {
					builder.readPreference(ReadPreference.nearest());
				}else if(readPreference.equalsIgnoreCase("primaryPreferred")) {
					builder.readPreference(ReadPreference.primaryPreferred());
				}else if(readPreference.equalsIgnoreCase("secondary")) {
					builder.readPreference(ReadPreference.secondary());
				}
			}
			
			MongoClientOptions mongoClientOptions = builder.build();
			// MongoDB地址列表
			List<ServerAddress> serverAddresses = new ArrayList<>();
			for (String address : addressList) {
				String[] hostAndPort = address.split(":");
				String host = hostAndPort[0];
				Integer port=27017;
				if(hostAndPort.length>1) {
					port = Integer.parseInt(hostAndPort[1]);
				}
				ServerAddress serverAddress = new ServerAddress(host, port);
				serverAddresses.add(serverAddress);
			}
			
			MongoClient mongoClient;
			if(StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password)) {
				//认证链接
				MongoCredential mongoCredential = MongoCredential.createScramSha1Credential(username,authenticationDatabase,password.toCharArray());
				mongoClient = new MongoClient(serverAddresses, mongoCredential, mongoClientOptions);
			}else {
				//无需认证链接
				mongoClient = new MongoClient(serverAddresses, mongoClientOptions);
			}
			
			return mongoClient;
		}
	
	}